# 字符编码

# 一、国际标准编码体系

# ASCII

# 历史背景

  • 由电报码发展而来,定义 128 个字符(33 控制字符 + 95 可显示字符)
  • IANA (opens new window) 官方名称 US-ASCII

# 编码结构

  • 控制字符(0-31、127)

    • 详细对照表(二进制/十进制/十六进制/Unicode 表示)
    • 典型应用:文本格式控制(换行、回车等)
  • 可显示字符(32-126)

# 控制字符

ASCII 控制字符的编号范围是 0-31 和 127,共 33 个字符。

为方便人类用户阅读,各个控制字符均有 Unicode 表示法和脱出字符表示法:

二进制 十进制 十六进制 缩写 Unicode 表示法 脱出字符表示法 名称
0000 0000 0 00 NUL ^@ 空字符
0000 0001 1 01 SOH ^A 标题开始
0000 0010 2 02 STX ^B 本文开始
0000 0011 3 03 ETX ^C 本文结束
0000 0100 4 04 EOT ^D 传输结束
0000 0101 5 05 ENQ ^E 请求
0000 0110 6 06 ACK ^F 确认回应
0000 0111 7 07 BEL ^G 响铃
0000 1000 8 08 BS ^H 退格
0000 1001 9 09 HT ^I 水平定位符号
0000 1010 10 0A LF ^J 换行键
0000 1011 11 0B VT ^K 垂直定位符号
0000 1100 12 0C FF ^L 换页键
0000 1101 13 0D CR ^M 回车键
0000 1110 14 0E SO ^N 取消变换
0000 1111 15 0F SI ^O 启用变换
0001 0000 16 10 DLE ^P 跳出数据通讯
0001 0001 17 11 DC1 ^Q 设备控制一
0001 0010 18 12 DC2 ^R 设备控制二
0001 0011 19 13 DC3 ^S 设备控制三
0001 0100 20 14 DC4 ^T 设备控制四
0001 0101 21 15 NAK ^U 确认失败回应
0001 0110 22 16 SYN ^V 同步用暂停
0001 0111 23 17 ETB ^W 区块传输结束
0001 1000 24 18 CAN ^X 取消
0001 1001 25 19 EM ^Y 连线介质中断
0001 1010 26 1A SUB ^Z 替换
0001 1011 27 1B ESC ^[ 退出键
0001 1100 28 1C FS ^\ 文件分割符
0001 1101 29 1D GS ^] 组群分隔符
0001 1110 30 1E RS ^^ 记录分隔符
0001 1111 31 1F US ^_ 单元分隔符
0111 1111 127 7F DEL ^? 删除键

# ISO 8859 系列

# ISO 8859-1

ISO 8859-1 是国际标准化组织内 ISO/IEC 8859 的第一个 8 位字符集。

  • ASCII 扩展(0xA0 - 0xFF 新增 96 字符)
  • 拉丁语系支持
  • 与 Windows-1252 的区别:
    • 码位 128 - 159 的字符差异
    • 浏览器兼容处理机制

# 与 Unicode 关系

  • 对应 Unicode 前 256 码位
  • 多语言扩展的实现限制

# 与 Windows-1252 区别

Windows 为了支持英语和西欧字符,设计了一个编码,对应的代码页是 1252,因此被称为 Windows-1252。

Windows-1252 的设计,参考了 ANSI 草案,而 ANSI 草案后来发展成为正式的国际标准:ISO 8859-1。

ISO-8859-1 与 Windows-1252 代码页的区别是:

  • 码位 128 - 159(0x80 - 0x9F)原本是罕用的 C1 控制字符编码范围,被替换为额外的一些常用但未包含在 ISO-8859-1 中的字符。

将 Windows-1252 文本误标为 ISO-8859-1,最常见的后果是所有引号和撇号[^1]在非 Windows 操作系统都变成问号或方格。

为了解决此问题,现在大部分网页浏览器和电邮用户端都将 MIME 字元集 ISO-8859-1 视作 Windows-1252 处理。

这也是 HTML5 标准要求的处理方式,要求将自称是 ISO-8859-1 的文件视作 Windows-1252 编码。

# Unicode 体系

Unicode 是一种信息技术标准,用于对世界上大多数书写系统中表达的文本进行一致的编码、表示和处理。

# 核心特性

  • 统一字符集(U + 十六进制表示法)
  • 基本多文种平面(BMP)与辅助平面
  • 私用区应用实例(如苹果图标 U+F8FF)

Unicode 为每一个字符定义唯一的代码,同时,其首 256 个字符保留给 ISO 8859-1 所定义的字符,使既有的西欧语系文字的转换不需特别考量。

在表示一个 Unicode 的字符时,通常会用 U+ 然后紧接着一组十六进制的数字来表示这一个字符。

基本多文种平面 (opens new window)里的所有字符,要用四个数字,即 2 字节,共支持六万多个字符;在零号平面以外的字符则需要使用五或六个数字。

# 字符平面映射

Unicode 将编码空间分成 17 个平面,以 0 到 16 编号。

基本多文种平面,即第 0 平面中的码点,都可以用一个 UTF-16 单位来编码,或者以 UTF-8 来编码的话,会使用一、二或三个字节。

而第 1 到 16 平面中的码点,UTF-16 会以代理对的方式来使用,而 UTF-8 则会编码成 4 个字节。

# 私用区

私人使用区位于零号平面 U+E000U+F8FF,15 号平面 U+F0000U+FFFFF 和 16 号平面 U+100000U+10FFFF

例如,苹果公司图标是 U+F8FF,即,当你用苹果提供的字体时,就能看到了。

# 编码实现

UTF-8 使用一至四个字节为每个字符编码:

  • 128 个 US-ASCII 字符只需一个字节编码
  • 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码
  • 其他基本多文种平面中的字符使用三个字节编码
  • 其他极少使用的 Unicode 辅助平面的字符使用四个字节编码

UTF-16 编码机制:

  • 代理对实现原理
  • 平面映射关系

# 二、中文编码标准

# GB 系列

# GB2312(1980)

GB/T 2312-1980 是中华人民共和国国家标准简体中文字符集,全称《信息交换用汉字编码字符集 基本集》。

  • 分区结构(94 区 × 94 位)
  • 编码原理:
    • 区位码国标码机内码
    • 实际使用 87 个区(6763 汉字 + 682 符号)

GB/T 2312 中对所收汉字进行了分区处理,每区含有 94 个汉字或符号,共计 94 个区。实际上,GB/T 2312 只使用了 87 个区。

用所在的区和位来表示字符的方法称为区位码,即码位。

在 GB2312 内,每个汉字及符号的码位使用两个字节来表示。第一个字节称为高位字节,对应分区的编号;第二个字节称为低位字节,对应区段内的码位。

  • 兼容 ASCII

    GB 2312 遵循 ISO 2022 规范,为了避开 ASCII 字符中的不可显示字符 0x000x1F 及空格字符 0x20,非 ASCII 字符双字节编码范围为 0x21 0x210x7E 0x7E,十进制为 33 33126 126

    因此,在进行码位转换时,须将区码和位码分别加上 32 或 0x20 作为国标码

    因为国标码和通用的 ASCII 码冲突,部分厂商在 ISO 2022 的基础上把双字节字符的二进制最高位都从 0 换成 1,即相当于把 ISO 2022 的每个字节都再加上 128 或 0x80 得到机内码表示,简称内码。

# GBK(1995)

汉字内码扩展规范,简称 GBK,由中华人民共和国全国信息技术标准化技术委员会制订。

  • 扩展特性:
    • 21886 字符(21003 汉字 + 883 符号)
    • 微软兼容实现
  • 技术特点:
    • 双字节扩展编码
    • 兼容 GB2312 的实现方式

由于 GB 2312-80 只收录了 6763 个汉字,有不少汉字没有收录在内。于是厂商微软利用 GB 2312-80 未使用的编码空间,收录 GB 13000.1-93 全部字符制定了 GBK 编码。

  • 兼容 GB2312

    GBK 向下完全兼容 GB2312-80 编码。

# GB18030(2000)

GB 18030,全称《信息技术 中文编码字符集》,是中华人民共和国国家标准所规定的变长多字节字符集。

  • 强制标准特性:

    • 变长编码(1/2/4字节)
    • 少数民族文字支持
    • Unicode 映射关系
  • 兼容性

    对 GB 2312-1980 完全向后兼容,与 GBK 基本向后兼容,并支持 GB 13000 的所有码位。

# 三、编码转换机制

# Quoted-printable

Quoted-printable 是使用可打印的 ASCII 字符表示各种编码格式下的字符,以便能在 7-bit 数据通路上传输 8-bit 数据。

  • 实现原理:
    • 8-bit 数据转 7-bit 可打印字符
    • 等号转义机制(=XX)
  • 应用场景:
    • 电子邮件编码
    • 二进制数据文本化

任何 8-bit 字节值可编码为 3 个字符:一个等号 = 后跟随两个十六进制数字表示该字节的数值。

除了可打印 ASCII 字符与换行符以外,所有字符必须表示为这种格式。

所有可打印 ASCII 字符可用 ASCII 字符编码来直接表示,但是等号 = 不可以这样直接表示。

# 百分号编码

百分号编码,又称 URL 编码,是特定上下文的统一资源定位符 URL 的编码机制。

# 编码规范

URI 所允许的字符分作保留与未保留。保留字符是那些具有特殊含义的字符,例如,斜线字符用于不同部分的分界符;未保留字符没有这些特殊含义。

百分号编码把保留字符表示为特殊字符序列。

  • 保留字符转义机制(%XX)
  • 非 ASCII 字符处理流程: 字符 → UTF-8 → 十六进制转义

百分号编码一个保留字符,首先需要把该字符的 ASCII 的值表示为两个 16 进制的数字,然后在其前面放置转义字符 %,置入 URI 中的相应位置。

对于非 ASCII 字符,需要转换为 UTF-8 字节序,然后每个字节按照上述方式表示。

# 标准差异

URI (opens new window) 规范和 W3C (opens new window) 规范有部分内容不一致。

例如空格,URI 规范将其转为 %20,W3C 规范将其转为 +

  • RFC 3986 规范:
    • 空格转为 %20
    • 严格 URI 编码规则
  • W3C 规范:
    • 空格转为 +
    • 表单数据编码实践

# Reference

[^1]: 弯引号,又称智能引号或印刷引号,由 Microsoft 软件的 "smart quotes" 功能产生,位于 Windows-1252 中 0x91-0x94 范围内。